package com.df.my_net_game.game_rpc.client;

import com.df.my_net_game.game_rpc.client.annotation.GRpc;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

@Slf4j
@Component
public class GRpcServiceAutoware implements BeanPostProcessor, ApplicationContextAware {
    ApplicationContext applicationContext;
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //动态创建实例
        Field[] declaredFields = bean.getClass().getDeclaredFields();
        try {
            for (Field field : declaredFields) {

                GRpc annotation = field.getAnnotation(GRpc.class);
                if (annotation == null) {
                    continue;
                }
                field.setAccessible(true);
                if(!field.getType().isInterface()){
                    throw new RuntimeException("@GRpc 标注的字段只能是接口类型！");
                }
                Object fieldObj = applicationContext.getBean(field.getType());
                if(fieldObj != null){
                    field.set(bean,fieldObj);
                }
                DynamicType.Builder<?> builder = new ByteBuddy().subclass(field.getType())
                        .name("");
                //创建代理，并放入容器
                //包括父接口
                Method[] methods = field.getType().getMethods();
                for (Method method : methods) {
                    method.setAccessible(true);
                    //生成
                    //TODO 有@GRpcReq的才发消息，没有的则抛出异常
//                    builder.method(ElementMatchers.named(method.getName())
//                            .and(ElementMatchers.hasParameters(parameterDescriptions -> method.getParameters()))
//                            .and(ElementMatchers.returns(method.getReturnType()))
//                    ).intercept(Implementation.Simple.)
                }

            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
